En POODR 2ª edición, página 125, Sandy Metz escribe
Hay dos mensajes nuevos, default_chain y default_tire_size, enviados en las líneas 6 y 7 a continuación. ... Envolver los valores predeterminados en métodos es una buena práctica en general
El código al que se refiere está debajo. Observe cómo se establece el valor predeterminado para chain y tire_size .
class Bicycle attr_reader :size, :chain, :tire_size def initialize(**opts) @size = opts[:size] @chain = opts[:chain] || default_chain @tire_size = opts[:tire_size] || default_tire_size end def default_chain # <- common default "11-speed" end def default_tire_size # <- common default "2.1" end end ¿Por qué este enfoque es mejor que el método familiar de simplemente establecer el valor predeterminado dentro de initialize() , es decir
def initialize(chain: "11-speed", tire_size:"2.1", **opts):Este libro trata sobre el diseño de programación orientada a objetos, por lo que supongo que la respuesta tiene algo que ver con una buena práctica de programación orientada a objetos, pero no estoy seguro de qué.
Los métodos son más fáciles de trabajar. Puede agregarlos en las pruebas o cambiar la implementación (cargar valores desde un archivo de configuración o algo así), todo sin tocar el código que los usa.
Pero la mayor diferencia entre su código y lo que sugiere Sandi es el manejo de valores falsos.
En su código, es posible pasar nils explícitamente en lugar del valor predeterminado.
Bicycle.new(chain: nil, tire_size: "2.1", ...) Puede que no sea un cero codificado en su código, sino que provenga de otro lugar. Independientemente, Bicycle lo aceptará y luego puede fallar en el tiempo de ejecución cuando intente usar el valor.
Mientras que el código del libro no acepta valores nulos, sin importar si es un valor nulo predeterminado o se envía explícitamente. Si chain es falsa, se utilizará "11-speed" .
El uso de un método modulariza el código para que las subclases puedan anular el comportamiento sin anular el inicializador:
class MountainBike < Bicycle def default_tire_size '18' end end Si usó argumentos posicionales initialize(chain="11-speed", tire_size="2.1", **opts) esto en realidad es una degradación importante, ya que ahora debe recordar el orden de los argumentos. Los argumentos posicionales solo deben usarse cuando hay un orden obvio en los argumentos.
En realidad, puede establecer los valores predeterminados para los argumentos posicionales y de palabras clave en la lista de argumentos con un método como este:
class Bicycle attr_reader :size, :chain, :tire_size def initialize(tire_size: default_tire_size, chain: default_tire_size, **opts) end # ... endSin embargo, no se hace muy a menudo, ya que tiende a desordenar mucho la firma del método.